/**
 * @author      William Nerini <wnerini@gmail.com>
 * @since       2012-04-23
 */

/*    Controller Base Class
 *        This class implements the base implementations/stubs for the methods and events required to implement a controller object. With the code
 *  below, the context of "this" in any user-supplied event handlers will always be the UI control itself and not the jQuery element, arguments
 *  or other divergent contexts.
*
 *    @param    name    	string    The HTML ID of the "view" fragment. Used as a name for loading the fragment as well as the default data call.
 *    @param    target    	string    The HTML ID of the parent element into which this  control should be drawn.
 *    @param    props    	object    An object containing additional object properties to set. All parameters are optional.
 *									  Base Parameters are:
 *										headless	true/false	This control does not need a view loaded from the server.
 *										css			object		An object containing CSS settings, applied directly to the control @ runtime, after all other css.
 *										class		string		The value for this controls "class" attribute, if any.
 *										model		object		A standard DataModel object, pre instantiated.
 *
 *  @requires    jQuery.js, ControllerException.js
 */
 const VIEW_URL = '/app/views/';
 
 define(["jquery", "ControllerException"], function($, ControllerException) {
 
        function ControllerBase(name, target, props) {
			// private members
			var _headless;
			var _cssClass;
			var _css;
			var _data;
            var _target;
			var _parent;
			var _id;
			var _thisElement;
			var _eventHandlers;
			var _allowedEvents;
			
			
			// Initialize default _eventHandlers, _allowedEvents and _css arrays.
			_eventHandlers = new Array();
			_allowedEvents = ['loaded', 'unloaded', 'reloaded'];			
			_css = new Array();
			
			
			// Set Control/Object ID
			if (!name) throw new ControllerException('Must provide "name" for object.', 30000001, 'ControllerBase()', 'ControllerBase.js', null);
			else _id = (name) ? name : 'ControllerBase';
			
			//Process the target element, by ID and generate a pretrieved jQuery ofbject for it.
			if (target) {
				_target = target;
				_parent = $('#' + target);
			}
			
			// Handle/allocate any user-supplied properties.
			if (props) {
				// process the associative array containing other arguments.
				_headless = (props['headless']) ? props['headless'] : false;
				_css = (props['css']) ? props['css'] : new Array();
				_cssClass = (props['class']) ? props['class'] : '';
				_data = (props['model']) ? props['model'] : null;
			}
			
			// Public accessors for private members. 
			ControllerBase.prototype.__defineGetter__("id", function() { return _id; });
			ControllerBase.prototype.__defineSetter__("id", function(x) { _id = x; });
			ControllerBase.prototype.__defineGetter__("class", function() { return _cssClass; });
			ControllerBase.prototype.__defineSetter__("class", function(x) { _cssClass = x; });			
			ControllerBase.prototype.__defineGetter__("self", function() { return _thisElement; });
			ControllerBase.prototype.__defineSetter__("data", function(x) { _data = x; });


			// Public accessor allowing inheriting classes to add event types to the base. AKA a "Protected" member implementation.
			ControllerBase.prototype.__defineSetter__("__events__", function(x) { _allowedEvents.push(x); });			



			// Public methods.
			//
			/* init()
			 * 		Used to instantiate any variables, data or views, before showing the control.
			 * 	Any time-consuming operations related to setting up the control should occur here.
			 */
			ControllerBase.prototype.init = function() {
				var randomSeed;
				
				if (!_headless) {
					// block "parent", then load the "view" fragment into it, and then hide the fragment.
					randomSeed = new Date().getTime();
					$.ajax(VIEW_URL + _id + ".html?v=" + randomSeed, { async: false, 
					                                                   contentType: "text/html", 
																	   success: function(result) { 
																	  								 $('<div></div>').attr('id', _id).html(result).appendTo(_parent);
																				 					_thisElement = $('#' + _id);

																		 						 }
																	 }
					);
					//_thisElement.hide();
					return true;
				}
				return true;
	
			};
			
			 /* render()
			 *   Render the current control, if applicable. Must be overridden by inheriting controls.
			 */
			ControllerBase.prototype.render = function () { 
				console.log('ControllerBase.render() called');
				_parent.html('ControllerBase.render() called')
				// Does nothing, by default. 
	
			}; 

			/* css([string|object], string)
			 * Sets a single css value, a complete css set or removes a single value from this object's CSS collection.
			 */
			ControllerBase.prototype.css = function(name, value) {
				if (!name) return _css;
				if (typeof value === 'undefined') {
					if (name instanceof Object) _css = name; // set the whole css property.
					else return _css[name]; // get the value specified by the string "x".
				}
				else {
					if (value === '') delete _css[name]; // clear a specific property
					else _css[name] = value; // set a specific value.
				}
			};

			
			/* show()
			 *   Show the current control, if applicable. May be overridden by inheriting controls.
			 */
			ControllerBase.prototype.show = function () {
				console.log("ControllerBase.show()");
				_thisElement.show();
	
			};
	
			/* hide()
			 *   Hide the current control, if applicable. May be overridden by inheriting controls.
			 */
			ControllerBase.prototype.hide = function () {
				_thisElement.hide();
			};
	
			/* toString()
			 *
			 */
			ControllerBase.prototype.toString = function() {
				return 'ControllerBase';
	
			};
	
			/* bind()
			 *   Bind an event handler to the current control, if applicable. May be overridden by inheriting controls.
			 */
			ControllerBase.prototype.bind = function(evt, func) {
				if (_allowedEvents.indexOf(evt) > -1) {
					if (typeof _eventHandlers[evt] === 'undefined') _eventHandlers[evt] = new Array();
					if (_eventHandlers[evt].indexOf(func) < 0) {
						_eventHandlers[evt].push(func);
						return true;
					}
					else return false;
				}
				return false;
	
			};
			
			/* fire()
			 *   Fire all handlers for a specific event, given the event info in "data". Maybe overridden by inheriting controls.
			 */
			ControllerBase.prototype.fire = function(evt, data) {
				if (_allowedEvents.indexOf(evt) > -1) {				
					if (_eventHandlers[evt].length > 0) {
						for (handler in _eventHandlers[evt]) {
							_eventHandlers[evt][handler](data); // ie: _evenHandlers['click'][handlerFunction](data);
						}
						return true;
					}
					else return false;
				}
				return false;
	
			};			


        };


		// 
        return ControllerBase;

 });